package utils;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Properties;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Stream;

import ini.DSTCluster;
import ini.DSTConf;
import ini.DSTServer;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.ini4j.Ini;
import com.fasterxml.jackson.databind.ObjectMapper;


public class Base {

    /**
     * 加载配置文件
     * @param filePath
     * @return
     */
    public static Properties loadConfig(String filePath) {
        Properties properties = new Properties();

        try (FileInputStream input = new FileInputStream(filePath)) {
            properties.load(input);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("load config fail.");
        }

        return properties;
    }

    public static String toJsonStr(Object object)
    {
        ObjectMapper mapper = new ObjectMapper();
        String jsonString = "";
        try {
            jsonString = mapper.writeValueAsString(object);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }

        return jsonString;
    }

    /**
     * 获取文件夹下所有的子目录名
     * @param dir
     * @return
     */
    public static List<Path> getAllSubPathName(Path dir)
    {
        ArrayList<Path> res = new ArrayList<>();

        try {
            // 使用 DirectoryStream 过滤出子目录
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
                for (Path entry : stream) {
                    if (Files.isDirectory(entry)) {
                        res.add(entry);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("no dir: " + dir.toString());
        }

        return res;
    }

    /**
     * 递归删除目录及其内容
     * @param directory
     * @return
     */
    public static boolean deleteDirectory(File directory) {
        // 如果目录不存在，返回 false
        if (!directory.exists()) {
            return false;
        }

        // 获取目录中的文件和子目录
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                // 递归删除文件和子目录
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    file.delete(); // 删除文件
                }
            }
        }

        // 删除空目录
        return directory.delete();
    }

    /**
     * 验证是否是一个有效的存档
     * @param str
     * @return
     */
    public static boolean isValidArchive(String str) {
        // 正则表达式：一个字母，后跟一个@符号，后跟一个数字
        String regex = "[a-zA-Z]+@[0-9]+";
        boolean res = str.matches(regex);
        return res;
    }

    /**
     * 从文件中获取命令
     * @param filePath
     * @return List<String>
     */
    public static List<String> getcmds(String filePath)
    {
        List<String> lines = new ArrayList<>();
        try {
            lines = Files.readAllLines(Paths.get(filePath));

        } catch (IOException e) {
            e.printStackTrace();
        }
        return lines;
    }

    /**
     * 验证文件是否完整
     * @param archivefile
     * @param code
     * @return
     */
    public static boolean archVolatile(File archivefile, String code)
    {
        return false;
    }

    /**
     * 将文件夹directory压缩为tarGzFile
     * @param directory
     * @param tarGzFile
     */
    public static int compressDirectoryToTarGz(File directory,File tarGzFile) {
        try (FileOutputStream fos = new FileOutputStream(tarGzFile);
             GzipCompressorOutputStream gzos = new GzipCompressorOutputStream(fos);
             TarArchiveOutputStream tarOut = new TarArchiveOutputStream(gzos)) {
            tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
            addFilesToTar(tarOut, directory,"");
        } catch (IOException e) {
            e.printStackTrace();
            if (tarGzFile.exists())
            {
                tarGzFile.delete();
            }
            return -1;
        }

        return 0;
    }

    private static void addFilesToTar(TarArchiveOutputStream tarOut, File file, String base) throws IOException {
        String entryName = base + file.getName();

        if (file.isDirectory()) {
            // 添加目录条目
            TarArchiveEntry entry = new TarArchiveEntry(file, entryName + "/");
            tarOut.putArchiveEntry(entry);
            tarOut.closeArchiveEntry();

            // 递归添加子文件
            for (File child : file.listFiles()) {
                addFilesToTar(tarOut, child, entryName + "/");
            }
        } else {
            // 添加文件条目
            TarArchiveEntry entry = new TarArchiveEntry(file, entryName);
            tarOut.putArchiveEntry(entry);
            try (FileInputStream fis = new FileInputStream(file)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = fis.read(buffer)) != -1) {
                    tarOut.write(buffer, 0, len);
                }
            }
            tarOut.closeArchiveEntry();
        }
    }

    /**
     * 解压.tar.gz文件
     * @param tarGzFile
     * @param outputDir
     * @throws IOException
     */
    public static int extractTarGz(File tarGzFile, File outputDir) {
        if (!tarGzFile.exists()) {
            System.err.println(tarGzFile.toString() + " is not exist.");
            return -1;
        }

        try (InputStream fileInputStream = new FileInputStream(tarGzFile);
            GzipCompressorInputStream gzipInputStream = new GzipCompressorInputStream(fileInputStream);
            TarArchiveInputStream tarInputStream = new TarArchiveInputStream(gzipInputStream)) {

            TarArchiveEntry entry;
            while ((entry = tarInputStream.getNextTarEntry()) != null) {
                File outputFile = new File(outputDir, entry.getName());

                if (entry.isDirectory()) {
                    // 如果是目录，则创建目录
                    outputFile.mkdirs();
                } else {
                    // 如果是文件，则解压文件
                    try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
                        byte[] buffer = new byte[1024];
                        int length;
                        while ((length = tarInputStream.read(buffer)) != -1) {
                            outputStream.write(buffer, 0, length);
                        }
                    }
                }
            }
        }catch ( IOException e){
            e.printStackTrace();
            return -1;
        }

        return 0;
    }

    public static boolean unzip(Path zipfile, Path unziptopath)
    {
        return false;
    }

    public static List<String> readLastNLines(String filePath, int n) {
        LinkedList<String> lastNLines = new LinkedList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (lastNLines.size() == n) {
                    lastNLines.poll();  // 删除最旧的一行
                }
                lastNLines.add(line);  // 添加新的一行
            }
        } catch (Exception e) {
            System.err.println("readLastNLines error: ");
            e.printStackTrace();
        }
        return lastNLines;
    }

    public static boolean haveString(String filePath, String str) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // System.out.println("[debug] " + line);
                if (line.contains(str)) {
                    return true;
                }
            }
        } catch (Exception e) {
            System.err.println("readLastNLines error: ");
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 读取cluster.ini文件
     * @param clusterIniFile
     * @return
     */
    public static DSTCluster readClusterIni(File clusterIniFile){
        DSTCluster dstCluster = new DSTCluster();
        try {
            String sectionName = "";
            Ini ini = new Ini(clusterIniFile);
            sectionName = "MISC";
            dstCluster.setMax_snapshots(Integer.parseInt(ini.get(sectionName,"max_snapshots")));
            dstCluster.setConsole_enabled(Boolean.parseBoolean(ini.get(sectionName,"console_enabled")));
            sectionName = "SHARD";
            dstCluster.setShard_enabled(Boolean.parseBoolean(ini.get(sectionName,"shard_enabled")));
            dstCluster.setBind_ip(ini.get(sectionName,"bind_ip"));
            dstCluster.setMaster_ip(ini.get(sectionName,"master_ip"));
            dstCluster.setMaster_port(Integer.parseInt(ini.get(sectionName,"master_port")));
            dstCluster.setCluster_key(ini.get(sectionName,"cluster_key"));
            sectionName = "STEAM";
            dstCluster.setSteam_group_only(ini.get(sectionName,"steam_group_only"));
            dstCluster.setSteam_group_id(ini.get(sectionName,"steam_group_id"));
            dstCluster.setSteam_group_admins(ini.get(sectionName,"steam_group_admins"));
            sectionName = "NETWORK";
            dstCluster.setOffline_cluster(ini.get(sectionName,"offline_cluster"));
            dstCluster.setTick_rate(ini.get(sectionName,"tick_rate"));
            dstCluster.setWhitelist_slots(ini.get(sectionName,"whitelist_slots"));
            dstCluster.setCluster_password(ini.get(sectionName,"cluster_password"));
            dstCluster.setCluster_name(ini.get(sectionName,"cluster_name"));
            dstCluster.setCluster_description(ini.get(sectionName,"cluster_description"));
            dstCluster.setLan_only_cluster(ini.get(sectionName,"lan_only_cluster"));
            dstCluster.setCluster_intention(ini.get(sectionName,"cluster_intention"));
            dstCluster.setAutosaver_enabled(Boolean.parseBoolean(ini.get(sectionName,"autosaver_enabled")));
            sectionName = "GAMEPLAY";
            dstCluster.setMax_players(Integer.parseInt(ini.get(sectionName,"max_players")));
            dstCluster.setPvp(Boolean.parseBoolean(ini.get(sectionName,"pvp")));
            dstCluster.setGame_mode(ini.get(sectionName,"game_mode"));
            dstCluster.setPause_when_empty(Boolean.parseBoolean(ini.get(sectionName,"pause_when_empty")));
            dstCluster.setVote_enabled(Boolean.parseBoolean(ini.get(sectionName,"vote_enabled")));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        return dstCluster;
    }

    /**
     * 读取server.ini文件
     * @param serverIniFile
     * @return
     */
    public static DSTServer readServerIni(File serverIniFile){
        DSTServer dstServer = new DSTServer();
        try {
            String sectionName = "";
            Ini ini = new Ini(serverIniFile);
            sectionName = "SHARD";
            dstServer.setIs_master(Boolean.parseBoolean(ini.get(sectionName, "is_master")));
            dstServer.setName(ini.get(sectionName, "name"));
            dstServer.setId(ini.get(sectionName, "id"));
            sectionName = "STEAM";
            dstServer.setAuthentication_port(Integer.parseInt(ini.get(sectionName, "authentication_port")));
            dstServer.setMaster_server_port(Integer.parseInt(ini.get(sectionName, "master_server_port")));
            sectionName = "NETWORK";
            dstServer.setServer_port(Integer.parseInt(ini.get(sectionName, "server_port")));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return dstServer;
    }


    /**
     * 将DSTCluster类写到cluster.ini文件中
     * @param dstCluster
     * @param inputFile
     * @return
     */
    public static Boolean writerDSTClusterToIni(DSTCluster dstCluster,File inputFile){

        try(BufferedWriter writer = new BufferedWriter(new FileWriter(inputFile))){
            writer.write("[MISC]\n");
            if(dstCluster.getMax_snapshots() != null){
                writer.write("max_snapshots = " + dstCluster.getMax_snapshots() + "\n");
            }
            if(dstCluster.getConsole_enabled() != null){
                writer.write("console_enabled = " + dstCluster.getConsole_enabled() + "\n");
            }
            writer.write("[SHARD]\n");
            if (dstCluster.getShard_enabled() != null){
                writer.write("shard_enabled = " + dstCluster.getShard_enabled() + "\n");
            }
            if (dstCluster.getBind_ip() != null){
                writer.write("bind_ip = " + dstCluster.getBind_ip() + "\n");
            }
            if (dstCluster.getMaster_ip() != null){
                writer.write("master_ip = " + dstCluster.getMaster_ip() + "\n");
            }
            if (dstCluster.getMaster_port() != null){
                writer.write("master_port = " + dstCluster.getMaster_port() + "\n");
            }
            if (dstCluster.getCluster_key() != null){
                writer.write("cluster_key = " + dstCluster.getCluster_key() + "\n");
            }

            writer.write("[STEAM]\n");
            if(dstCluster.getSteam_group_only() != null){
                writer.write("steam_group_only = " + dstCluster.getSteam_group_only() + "\n");
            }
            if(dstCluster.getSteam_group_id() != null){
                writer.write("steam_group_id = " + dstCluster.getSteam_group_id() + "\n");
            }
            if(dstCluster.getSteam_group_admins() != null){
                writer.write("steam_group_admins = " + dstCluster.getSteam_group_admins() + "\n");
            }

            writer.write("[NETWORK]\n");
            if(dstCluster.getOffline_cluster() != null){
                writer.write("offline_cluster = " + dstCluster.getOffline_cluster() + "\n");
            }
            if(dstCluster.getTick_rate() != null){
                writer.write("tick_rate = " + dstCluster.getTick_rate() + "\n");
            }
            if(dstCluster.getWhitelist_slots() != null){
                writer.write("whitelist_slots = " + dstCluster.getWhitelist_slots() + "\n");
            }
            if(dstCluster.getCluster_password() != null){
                writer.write("cluster_password = " + dstCluster.getCluster_password() + "\n");
            }
            if(dstCluster.getCluster_name() != null){
                writer.write("cluster_name = " + dstCluster.getCluster_name() + "\n");
            }
            if(dstCluster.getCluster_description() != null){
                writer.write("cluster_description = " + dstCluster.getCluster_description() + "\n");
            }
            if(dstCluster.getLan_only_cluster() != null){
                writer.write("lan_only_cluster = " + dstCluster.getLan_only_cluster() + "\n");
            }
            if(dstCluster.getCluster_intention() != null){
                writer.write("cluster_intention = " + dstCluster.getCluster_intention() + "\n");
            }
            if(dstCluster.getAutosaver_enabled() != null){
                writer.write("autosaver_enabled = " + dstCluster.getAutosaver_enabled() + "\n");
            }

            writer.write("[GAMEPLAY]\n");
            if(dstCluster.getMax_players() != null){
                writer.write("max_players = " + dstCluster.getMax_players() + "\n");
            }
            if(dstCluster.getPvp() != null){
                writer.write("pvp = " + dstCluster.getPvp() + "\n");
            }
            if(dstCluster.getGame_mode() != null){
                writer.write("game_mode = " + dstCluster.getGame_mode() + "\n");
            }
            if(dstCluster.getPause_when_empty() != null){
                writer.write("pause_when_empty = " + dstCluster.getPause_when_empty() + "\n");
            }
            if(dstCluster.getVote_enabled() != null){
                writer.write("vote_enabled = " + dstCluster.getVote_enabled() + "\n");
            }
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }

        return true;
    }

    public static Boolean writerDSTServerToIni(DSTServer dstServer,File inputFile){
        try(BufferedWriter writer = new BufferedWriter(new FileWriter(inputFile))){
            writer.write("[SHARD]\n");
            if(dstServer.getIs_master() != null){
                writer.write("is_master = " + dstServer.getIs_master() + "\n");
            }
            if(dstServer.getName() != null){
                writer.write("name = " + dstServer.getName() + "\n");
            }
            if(dstServer.getId() != null){
                writer.write("id = " + dstServer.getId() + "\n");
            }
            writer.write("[STEAM]\n");
            if(dstServer.getAuthentication_port() != null){
                writer.write("authentication_port = " + dstServer.getAuthentication_port() + "\n");
            }
            if(dstServer.getMaster_server_port() != null){
                writer.write("master_server_port = " + dstServer.getMaster_server_port() + "\n");
            }
            writer.write("[NETWORK]\n");
            if(dstServer.getServer_port() != null){
                writer.write("server_port = " + dstServer.getServer_port() + "\n");
            }
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }

        return true;
    }

}

